﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using StaticPlugin;

namespace StaticPlugin
{
    class Executer
    {
        //TODO: сделать по типу операционной системы
        private WebBrowser browser;
        List<AJob> jobs;

        // сортировка по приоритету
        // unsafe: не принимает null
        //private static int JobsSorter(AJob j1, AJob j2) 
        //{
        //    if (j1 == null || j2 == null) throw new Exception("Сортировщику передан нулевой указатель");
        //    if (j1.Priority < j2.Priority) return 1;
        //    if (j1.Priority == j2.Priority) return 0;
        //    return -1;
        //}

        public Executer(WebBrowser b, List<AJob> j) 
        {
            browser = b; jobs = j;
            //jobs.Sort(JobsSorter);
            browser.Navigating += new WebBrowserNavigatingEventHandler(browser_Navigating);
            browser.Navigated += new WebBrowserNavigatedEventHandler(browser_Navigated);
        }

        #region Busy browser object.. bool BrowserBusy
        void browser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            BrowserBusy = false;
        }

        bool BrowserBusy = false;

        void browser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
        {
            BrowserBusy = true;
        }
        #endregion

        private AJob activeJob = null;
        int activeJobNum = -1;

        internal int Ping()
        {
            if (browser.IsBusy || BrowserBusy)  // если browser занят ничего не делаем
            {
                return activeJobNum;
            }


            AJob needActivating = null;

            foreach (AJob j in jobs) // определяем задачу которую надо запустить
            {
                if (j.testRequirements(browser)) if (j.Available)
                    {
                        if (needActivating == null)
                        {
                            needActivating = j;
                            continue;
                        }
                        if (j.Priority < needActivating.Priority) // если значение Priority меньше (приоритет выше)
                        {
                            needActivating = j;
                            continue;
                        }
                    }
            }
            // выбрана задача с наивысшим приоритетом на данный момент.

            if (activeJob != null) // уже что-то крутится
            {
                // Разбираемся надо ли прерывать текущую задачу ради критической
                
                if(needActivating != null) if (activeJob.Priority >= 0 && needActivating.Priority < 0)
                {
                    Console.WriteLine("Бросаем активную задачу ради критической");
                    dropActiveJob();
                    ActivateJob(needActivating);
                }
            }
            else if(needActivating != null) ActivateJob(needActivating);
            
            // есть активная задача?
            if (activeJob != null && activeJob.getActions().Count>0)
            {
                AJob.Action act = activeJob.getActions()[0];
                Console.WriteLine("executer:: exec action: " + act.name);
                act.func(browser);
                if (activeJob.getActions().Count > 0)
                    activeJob.getActions().RemoveAt(0);
            }

            if (activeJob != null)
            {
                if (activeJob.getActions().Count == 0) // Кончились действия
                {
                    Console.WriteLine("Действия задачи '" + activeJob.Name + "' кончились");
                    dropActiveJob();
                }
            }
            return activeJobNum;
        }

        private void ActivateJob(AJob j)
        {
            activeJob = j; // активируем задачу
            activeJobNum = jobs.IndexOf(activeJob);
            activeJob.initActions();
            Console.WriteLine("ActivateJob(" + activeJob.Name + ")");
        }

        private void dropActiveJob()
        {
            if (activeJob == null) return;
            activeJob.initActions();
            Console.WriteLine("dropped active job '" + activeJob.Name + "'");
            activeJob = null;
            activeJobNum = -1;
        }
    }
}
